package com.inepex.graphicstests.client.misc;

import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.user.client.Random;
import com.inepex.inegraphics.impl.client.canvas.CanvasWidget;
import com.inepex.inegraphics.shared.Context;
import com.inepex.inegraphics.shared.gobjects.Circle;
import com.inepex.inegraphics.shared.gobjects.GraphicalObject;
import com.inepex.inegraphics.shared.gobjects.Path;
import com.inepex.inegraphics.shared.gobjects.Rectangle;

public class GraphicalObjectFactory {

	private enum GOType{
		Rect,
		RoundedCRect,
		Circle,
		Triangle
	}

	static final String[] flotColorSet = { new String("#edc240"),
		new String("#afd8f8"), new String("#cb4b4b"), new String("#4da74d"),
		new String("#9440ed"), new String("#1c91db"), new String("#dfd212"),
		new String("#de8238") };

	static final String[] ineColorSet = {
		new String("#1c91db"),
		new String("#dfd212"),
		new String("#de8238"),
		new String("#e4292d"),
		new String("#12e8de"),
		new String("#b6c317"),
		new String("#f5a032"),
		new String("#fb3f21"),
		new String("#0fcbf2"),
		new String("#d5b914"),
		new String("#eba626"),
		new String("#f15b1f")
	};

	private static int actual = 0;
	private static String[] colors = flotColorSet;

	public static String getNextColor() {
		if (actual >= colors.length)
			actual = 0;
		return colors[actual++];
	}

	public static GraphicalObject getSimpleRect(){
		Rectangle rect = new Rectangle(0, 0, Globals.simpleSquareWidth, Globals.simpleSquareWidth, 0, true, true, getOpaqueContext(getNextColor()), 0);
		return rect;
	}

	public static GraphicalObject getSimpleCircle(){
		return new Circle(0, 0, Globals.simpleCircleRadius, true, true, getOpaqueContext(getNextColor()), 0);
	}

	public static GraphicalObject getRandomGraphicalObjectWithNullContext(){
		GOType goType = GOType.values()[Random.nextInt(GOType.values().length)];
		GraphicalObject go = null;
		boolean fill = Random.nextBoolean();
		boolean stroke = Random.nextBoolean();
		switch (goType) {
		case Circle:
			go = new Circle(0, 0, Globals.simpleCircleRadius, stroke, fill, null, 0);
			break;
		case Rect:
			go = new Rectangle(0, 0, Globals.simpleSquareWidth, Globals.simpleSquareWidth, 0, stroke, fill, null, 0);
			break;
		case RoundedCRect:
			go = new Rectangle(0, 0, Globals.simpleSquareWidth, Globals.simpleSquareWidth, Random.nextInt(20), stroke, fill, null, 0);
			break;
		case Triangle:
			Path p = new Path(0, 0, stroke, fill, 0, null);
			p.setAlignElementsWithBasePoint(true);
			p.lineTo(Math.PI/3, Globals.simpleTriangleSide);
			p.lineTo(-Math.PI/3, Globals.simpleTriangleSide);
			p.lineToBasePoint();
			go = p;
			break;
		}

		return go;
	}

	public static Context getOpaqueContext(String color){
		return new Context(1.0, "black", 1.0, color);
	}

	public static Context getRandomContext_WithoutShadows(){
		double alpha = 0.000001 + Random.nextDouble();
		double strokeWidth = Random.nextDouble() * 10;
		String stroke = ineColorSet[Random.nextInt(ineColorSet.length)];
		String fill = ineColorSet[Random.nextInt(ineColorSet.length)];
		return new Context(alpha, stroke, strokeWidth, fill);
	}

	private static int rect_distanceFromOrigin = 0;
	private static boolean increasing = true;

	public static GraphicalObject getSimpleRectWithMove(){
		Rectangle r = (Rectangle) getSimpleRect();
		setSimpleRectsPosition(r);
		return r;
	}

	public static void setSimpleRectsPosition(Rectangle rect){
		if(increasing && 
				(rect_distanceFromOrigin + Globals.simpleSquareWidth >= Globals.width || rect_distanceFromOrigin + Globals.simpleSquareWidth >= Globals.height)){
			increasing = false;
		}
		else if(!increasing && 
				(rect_distanceFromOrigin <= 0 || rect_distanceFromOrigin <= 0)){
			increasing = true;
		}

		rect.setBasePointX(rect_distanceFromOrigin);
		rect.setBasePointY(rect_distanceFromOrigin);

		if(increasing){
			rect_distanceFromOrigin++;
		}
		else{
			rect_distanceFromOrigin--;
		}

	}

	public static void setNextContext(GraphicalObject go){
		go.setContext(getOpaqueContext(getNextColor()));
	}

	public static void setRandomPosition(GraphicalObject go){
		int x = Random.nextInt(Globals.width);
		int y = Random.nextInt(Globals.height);

		//		if(go instanceof Path){
		//			go.s
		//		}
		go.setBasePointX(x);
		go.setBasePointY(y);
	}

	public static void generateRandomShapeOnCanvas(Object canvas){
		GOType goType = GOType.values()[Random.nextInt(GOType.values().length)];
		boolean fill = Random.nextBoolean();
		boolean stroke = Random.nextBoolean();
		int[] position = getRandomPositionOnCanvas();
		generateRandomContextOnCanvas(canvas);
		if(canvas instanceof CanvasWidget){
			((CanvasWidget) canvas).beginPath();
			switch (goType) {
			case Circle:
				((CanvasWidget) canvas).arc(position[0], position[1], Globals.simpleCircleRadius, 0, 2 * Math.PI, false);
				break;
			case RoundedCRect:
				//FIXME
			case Rect:
				((CanvasWidget) canvas).rect(position[0], position[1], Globals.simpleSquareWidth, Globals.simpleSquareWidth);
				break;
			case Triangle:
				((CanvasWidget) canvas).moveTo(position[0], position[1]);
				((CanvasWidget) canvas).lineTo(position[0] + Globals.simpleTriangleSide / 2, position[1] - Globals.simpleTriangleSide);
				((CanvasWidget) canvas).lineTo(position[0] + Globals.simpleTriangleSide, position[1]);
				((CanvasWidget) canvas).closePath();
			}
			if(stroke){
				((CanvasWidget) canvas).stroke();
			}
			if(fill){
				((CanvasWidget) canvas).fill();
			}
		}
		else if(canvas instanceof Context2d){

		}
	}

	public static void generateRandomContextOnCanvas(Object canvas){
		if(canvas instanceof CanvasWidget){
			((CanvasWidget) canvas).setFillStyle(ineColorSet[Random.nextInt(ineColorSet.length)]);
			((CanvasWidget) canvas).setStrokeStyle(ineColorSet[Random.nextInt(ineColorSet.length)]);
			((CanvasWidget) canvas).setGlobalAlpha(Random.nextDouble());
			((CanvasWidget) canvas).setLineWidth(Random.nextDouble() * 5);
		}
	}

	public static int[] getRandomPositionOnCanvas(){
		return new int[]{Random.nextInt(Globals.width), Random.nextInt(Globals.height)};
	}
	
	public static Path generateCurvyPath(int points){
		double lastX = 0;
		double xDiff = Globals.width / (double)points;
		double yDiff = Globals.height / 25d;
		double lastY = nextY(Globals.height / 2, yDiff);
		Path path = new Path(lastX, lastY);
		for(int i = 1; i < points; i++){
			lastY = nextY(lastY, yDiff);
			lastX += xDiff;
			path.lineTo(lastX, lastY, false);
		}
		path.setContext(new Context(1.0, flotColorSet[0], 6.3, "black"));
		path.setStroke(true);
		path.setFill(false);
		return path;
	}
	
	protected static double nextY(double lastY, double maxDiff){
		double newX = lastY + (Random.nextDouble() - 0.5) * maxDiff * 2;
		return Math.max(0, Math.min(Globals.height, newX));
		
	}
}
